package com.uuah.server.transport.retry.policies;

import java.io.InterruptedIOException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.uuah.server.api.transport.retry.IRetryCallback;
import com.uuah.server.api.transport.retry.IRetryContext;
import com.uuah.server.api.transport.retry.IRetryNotifier;
import com.uuah.server.api.transport.retry.IRetryPolicy;
import com.uuah.server.api.transport.retry.RetryPolicyTemplate;
import com.uuah.server.exception.retry.RetryPolicyExhaustedException;
import com.uuah.server.transport.retry.PolicyStatus;
import com.uuah.server.transport.retry.RetryContext;
import com.uuah.server.transport.retry.notifiers.ConnectNotifier;

/**
 * Base class for PolicyFactory implementations TODO comment ...
 *
 * <p>
 * update record:updator，update time，update content and version
 * </p>
 *
 * @author <a href="jonny_quan@hotmail.com">jonny</a>
 * @date 2009 2009-3-27 下午02:47:39
 * @version 1.0.0
 */
public abstract class AbstractPolicyTemplate implements RetryPolicyTemplate {
	protected transient final Logger logger = LoggerFactory
			.getLogger(getClass());
	protected boolean connectAsychronously = false;

	protected IRetryNotifier notifier = new ConnectNotifier();

	public IRetryContext execute(IRetryCallback callback) throws Exception {
		PolicyStatus status = null;
		IRetryPolicy policy = createRetryInstance();
		RetryContext context = new RetryContext(callback.getWorkDescription());
		try {
			Exception cause = null;
			do {
				try {
					callback.doWork(context);
					if (notifier != null) {
						notifier.sucess(context);
					}
					break;
				} catch (Exception e) {
					cause = e;
					if (notifier != null) {
						notifier.failed(context, cause);
					}
					if (cause instanceof InterruptedException
							|| cause instanceof InterruptedIOException) {
						logger
								.error("Process was interrupted (InterruptedException), ceasing process");
						break;
					} else {
						status = policy.applyPolicy(cause);
					}
				}
			} while (status.isOk());

			if (status == null || status.isOk()) {
				return context;
			} else {
				throw new RetryPolicyExhaustedException(cause, callback
						.getWorkDescription());
			}
		} finally {
			if (status != null && status.getThrowable() != null) {
				if (logger.isDebugEnabled()) {
					logger.debug("error", status.getThrowable().getMessage());
				}
			}
		}
	}

	public boolean isRetryEnabled() {
		return true;
	}

	public boolean isConnectAsynchronously() {
		return connectAsychronously;
	}

	public void setConectAsychronously(boolean connectAsychronously) {
		this.connectAsychronously = connectAsychronously;
	}

	public IRetryNotifier getNotifier() {
		return notifier;
	}

	public void setNotifier(IRetryNotifier retryNotifier) {
		this.notifier = retryNotifier;
	}
}
